/**
 * Created by Richard Radlherr.
 * Date: 09.07.2006 19:03
 */

using System;
using System.Text;
using CsGL.OpenGL;
using System.IO;

namespace TagTool.GraphicTypes
{
	
	public enum MoveState
	{
		Single = 0,
		Swarm  = 1
	}
	
	[Serializable()]
	public class Shape : CsGL.OpenGL.GL, IDisposable
	{
		protected PointD scale = new PointD(1.0 ,1.0, 1.0);
		protected PointD translate = new PointD();
		protected PointD rotate = new PointD(0.0, 0.0, 0.1);
		protected double angle;
		protected double radius;
		protected double zoomRange;

		protected uint glList = 0;
		
		private PointD zoom = new PointD(0.0, 0.0, 0.0);
		private PointD direction = new PointD();
		private double speed;
		private double spin;
		
		private MoveState moveState = MoveState.Swarm;
		
		protected double x1, y1, x2, y2;
		
		protected double alpha = 1.0;
		protected double fadeOut = 0.05;
		
		public Shape()
		{
			radius = 23.0;
			zoomRange = 20.0;
			Initialize();
		}
		
		public void Initialize() {
			Dispose();
			glList = glGenLists(1);
			Update();
		}
		
		public MoveState MoveState
		{
			get { return moveState; }
			set { moveState = value; }
		}
		
		
		
		public virtual double Alpha
		{
			get { return alpha; }
			set { 
				if (value != alpha)
				{
					alpha = value; 
				}
			}
		}
		
		public double FadeStep
		{
			get { return fadeOut; }
			set {
				if (value < 0)
				{
					fadeOut = 0.0;
				}
				else if (value > 1.0)
				{
					fadeOut = 1.0;
				}
				else 
				{
					fadeOut = value;
				}
			}
		}
		
		public void FadeOut()
		{
			if (fadeOut > 0.0 && alpha > 0.0)
			{
				this.Alpha = alpha - fadeOut;	
			}
		}
		
		public virtual void Dispose()
		{
			if (glIsList(glList) == GL_TRUE)
			{
				glDeleteLists(glList, 1);
			}
		}
		
		/**
		 * This methosshall move the Shape so that its midpoint
		 * is in the center of the bounding box
		 */
		public virtual void SetPivot()
		{
		}

		public double Angle
		{
			get { return angle; }
			set { angle = value; }
		}
		
		public PointD Scale
		{
			get { return scale; }
			set { scale = value; }
		}
		
		public PointD Translate
		{
			get { return translate; }
			set { translate = value; }
		}
		
		public PointD Rotate
		{
			get { return rotate; }
			set { rotate = value; }
		}
		
		public PointD Direction
		{
			get { return direction; }
			set { direction = value; }
		}
		
		public PointD Zoom
		{
			get { return zoom; }
			set { zoom = value; }
		}
		
		public double Spin
		{
			get { return spin; }
			set { spin = value; }
		}
		
		public double Speed
		{
			get { return speed; }
			set { speed = value; }
		}
		
		/**
		 * Render the gl - List of this shape onto the current gl - context
		 */
		public virtual void Render()
		{
			if (glList != 0)
			{
				glPushMatrix();
				
				glTranslated(translate.X, translate.Y, translate.Z);
				glRotated(angle, rotate.X, rotate.Y, rotate.Z);
				glScaled(scale.X, scale.Y, scale.Z);
				glCallList(glList);

				glPopMatrix();
			}
			glFlush();
		}
		
		public virtual void Save(StreamWriter writer)
		{
			// do nothing
		}
		
		public virtual void Load(StreamReader reader)
		{
			// do nothing
		}
		
		private static String ReadString(Stream stream, char lastChar)
		{
			StringBuilder b = new StringBuilder();
			char ch;
			do
			{
				ch = (char)stream.ReadByte();
				if (ch != lastChar)
				{
					b.Append(ch);
				}
			}
			while (ch != lastChar);
			
			if (lastChar == (char)0x0d)
			{
				stream.ReadByte(); // skip 0x0a
			}
			
			return b.ToString();
		}
		
		public static bool ReadHeader(StreamReader reader, bool skip, String name)
		{
			long start = reader.BaseStream.Position;
			long len;
			try {
				String tag = ReadString(reader.BaseStream, (char)0x0d);
				long l = reader.BaseStream.Position;
				len = long.Parse(ReadString(reader.BaseStream, (char)0x0d));
				if (!tag.Equals(name))
				{
					if (skip)
					{
						reader.BaseStream.Seek(l + len, 0);
					}
					else
					{
						reader.BaseStream.Seek(start, 0);
					}
					return skip;
				}
				else
				{
					return true;
				}
				
			} catch
			{
				reader.BaseStream.Seek(start, 0);
				return false;
			}
		}
		
		/**
		 * Compile the actual gl List - call compile
		 */
		public void Update()
		{
			glNewList(glList, GL_COMPILE);

			Compile();
			
			glEndList();
		}
		
		/**
		 * contains the drawing commands for open gl to draw the
		 * Shape.
		 */
		protected virtual void Compile()
		{
			glBegin(GL_LINES);
			glEnd();
		}

		/**
		 * Updates the position an rotation of the object.
		 */
		public virtual void Move()
		{
			//direction = PointD.Origin;
			//zoom = PointD.Origin;
			//Console.WriteLine(angle + " " + spin + " " + direction + " " + translate + " " + scale + " " + zoom);
			angle += spin;
			radius = 18.0;
			translate +=  direction * speed;
			
			zoomRange = 2;
			
			scale += zoom * 2 * Math.Exp(scale.X); /* *zoomDir */  ;
			double l = scale.X;
			
			if (l > zoomRange)
			{
				scale = PointD.Origin;
			}
			else if (l <= 0.0)
			{
				scale = new PointD(1.0, 1.0, 1.0) * zoomRange;
			}
			
		
			double rad = 36;
			if ( translate.X >= rad)
			{
				translate.X = -translate.X + (translate.X - rad);
			}
			else if ( translate.X < -rad)
			{
				translate.X = rad + (translate.X + rad);
			}
				
			if ( translate.Y >= rad)
			{
				translate.Y = -translate.Y + (translate.Y - rad);
			}
			else if ( translate.Y < -rad)
			{
				translate.Y = rad + (translate.Y + rad);
			}

		}
		

	}
	
}
